#ifndef SOLVERS_SOLVERFACTORY_HPP
#define SOLVERS_SOLVERFACTORY_HPP
/*! \file solverFactory.hpp
 *  \author Zhao Chengpeng (chengpeng_zhao@foxmail.com)
 *  \date 2022-11-21
 *  \modified 2024-01-09
 *  \brief factory for solvers and preconditioners
 */

#include "unapMatrixSolver.hpp"
#include "unapPreconditioner.hpp"
#include "unapSmoother.hpp"

namespace UNAP {

typedef Preconditioner<scalar> *(*precondCreatorPtr)(const Matrix<scalar> &A);
class PrecondFactory {
 public:
  static HASHMAP<string, precondCreatorPtr> precondMap_;
  static Preconditioner<scalar> *buildPrecond(const Matrix<scalar> &A,
                                              string name) {
    HASHMAP<string, precondCreatorPtr>::const_iterator it =
        precondMap_.find(name);
    if (it == precondMap_.end()) {
      COUT << name << " is not a correct Preconditioner name." << ENDL;
      exit(1);
    }
    return it->second(A);
  }
};

typedef Solver<scalar> *(*solverCreatorPtr)(Preconditioner<scalar> &precond);
class SolverFactory {
 public:
  static HASHMAP<string, solverCreatorPtr> solverMap_;
  static Solver<scalar> *buildSolver(Preconditioner<scalar> &precond,
                                     string name) {
    HASHMAP<string, solverCreatorPtr>::const_iterator it =
        solverMap_.find(name);
    if (it == solverMap_.end()) {
      COUT << name << " is not a correct Solver name." << ENDL;
      exit(1);
    }
    return it->second(precond);
  }
};

typedef Smoother<scalar> *(*smootherCreatorPtr)(Communicator *comm);
class SmootherFactory {
 public:
  static HASHMAP<string, smootherCreatorPtr> smootherMap_;
  static Smoother<scalar> *buildSmoother(Communicator *comm, string name) {
    HASHMAP<string, smootherCreatorPtr>::const_iterator it =
        smootherMap_.find(name);
    if (it == smootherMap_.end()) {
      COUT << name << " is not a correct Smoother name." << ENDL;
      exit(1);
    }
    return it->second(comm);
  }
};

}  // namespace UNAP
#endif /* end of include guard: SOLVERS_SOLVERFACTORY_HPP */
